package ru.amse.tsyganov.jumleditor.editor;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import ru.amse.tsyganov.jumleditor.commands.ViewsManager;
import ru.amse.tsyganov.jumleditor.model.ActivityGraph;
import ru.amse.tsyganov.jumleditor.model.Partition;
import ru.amse.tsyganov.jumleditor.model.State;
import ru.amse.tsyganov.jumleditor.model.Transition;
import ru.amse.tsyganov.jumleditor.view.ActivityGraphView;
import ru.amse.tsyganov.jumleditor.view.PartitionView;
import ru.amse.tsyganov.jumleditor.view.StateView;
import ru.amse.tsyganov.jumleditor.view.TransitionView;

public class Editor {
	
	private static final String SHELL_CAPTION = "Editor";
	private static final int INITIAL_SHELL_WIDTH = 500;
	private static final int INITIAL_SHELL_HEIGHT = 400;
	private static final int TOOL_BAR_HEIGHT = 40;
	
	class PaintEventHandler implements PaintListener {
		
		public void paintControl(PaintEvent e) {
			GC gc = e.gc;
			for (PartitionView<Partition> p : actionGraphView.getPartitions()) {
				p.paint(gc);
			}
			
			for (PartitionView<Partition> p : actionGraphView.getPartitions()) {
				for (StateView<? extends State> s : p.getContents()) {
					for (TransitionView<Transition> t : 
						s.getStateVertex().getOutgoing()) {
					
						t.paint(gc);
					}
				}
			}
			
			for (PartitionView<Partition> p : actionGraphView.getPartitions()) {
				for (StateView<? extends State> s : p.getContents()) {
					s.paint(gc);
				}
			}
			
			editorMode.paintControl(e);
		}
	}
	
	class MouseEventsHandler implements MouseListener, MouseMoveListener {
		
		public void mouseDoubleClick(MouseEvent e) {
			assert e != null;
			editorMode.mouseDoubleClick(e);
		}
		public void mouseDown(MouseEvent e) {
			assert e != null;
			editorMode.mouseDown(e);
		}
		public void mouseUp(MouseEvent e) {
			assert e != null;
			editorMode.mouseUp(e);
		}
		public void mouseMove(MouseEvent e) {
			assert e != null;
			editorMode.mouseMove(e);
		}		
	}
	
	private Display display;
	private Shell sShell;  
	private Canvas canvas;
	private ActivityGraphView<ActivityGraph> actionGraphView;
	private ToolBar toolBar;
	
	private ViewsManager viewsManager;
	private EditorMode editorMode;
	
	public Editor(ActivityGraphView<ActivityGraph> activityGraphView) {
		this.actionGraphView = activityGraphView;
		final int VIEWS_MANAGER_SIZE = 20; 
		viewsManager = new ViewsManager(VIEWS_MANAGER_SIZE);
		createSShell();
		
		AddStateMode.instance.init(viewsManager, actionGraphView, canvas);
		DragFiguresMode.instance.init(viewsManager, actionGraphView, canvas);
		AddTransitionMode.instance.init(viewsManager, actionGraphView, canvas);
		
		editorMode = DragFiguresMode.instance;
		canvas.setCursor(editorMode.getCursor());
		openAndWaitEvents();
	}

	private void openAndWaitEvents() {
		sShell.open();
		
		while(!sShell.isDisposed()) {
		   if(!display.readAndDispatch()) {
		       display.sleep();
		   }
		}
		display.dispose();
	}

	/**
	 * This method initializes sShell
	 */
	private void createSShell() {
		display = new Display();
		sShell = new Shell(display);
		sShell.setText(SHELL_CAPTION);
		
		createToolBar();
		createCanvas();
				
		FormLayout formLayout = new FormLayout();
		formLayout.marginHeight = 0;
		formLayout.marginWidth = 0;
		formLayout.marginBottom = 0;
		formLayout.marginLeft = 0;
		formLayout.marginRight = 0;
		formLayout.marginTop = 0;
		sShell.setLayout(formLayout);
				
		sShell.setSize(new Point(INITIAL_SHELL_WIDTH, 
				INITIAL_SHELL_HEIGHT));
		
		assert sShell != null;
	}

	/**
	 * This method initializes canvas	
	 */
	private void createCanvas() {
		assert sShell != null;
		assert toolBar != null;
		
		canvas = new Canvas(sShell, SWT.NONE);
		
		Color lightGrayColor = 
			new Color(null, new RGB(247, 247, 247));
		
		canvas.setBackground(lightGrayColor);
		canvas.addPaintListener(new PaintEventHandler());
		
		MouseEventsHandler mouseEventsHandler = new MouseEventsHandler();
		canvas.addMouseListener(mouseEventsHandler);
		canvas.addMouseMoveListener(mouseEventsHandler);
		
		FormData canvasFormData = new FormData();
		canvasFormData.left = new FormAttachment(0, 0);
		canvasFormData.right = new FormAttachment(100, 0);
		canvasFormData.bottom = new FormAttachment(100, 0);
		canvasFormData.top = new FormAttachment(toolBar, 0);
		canvas.setLayoutData(canvasFormData);
		
		assert canvas != null;
	}
	
	/**
	 * This method initializes toolBar	
	 */
	private void createToolBar() {
		assert sShell != null;
		
		toolBar = new ToolBar(sShell, SWT.NONE);
		
		FormData toolBarFormData = new FormData();
		toolBarFormData.left = new FormAttachment(0, 0);
		toolBarFormData.right = new FormAttachment(100, 0);
		toolBarFormData.bottom = new FormAttachment(0, TOOL_BAR_HEIGHT);
		toolBarFormData.top = new FormAttachment(0, 0);
		toolBar.setLayoutData(toolBarFormData);
		
		ToolItem undoItem = new ToolItem(toolBar, SWT.PUSH);
		undoItem.setText("undo");
		undoItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				viewsManager.rollback();
				canvas.redraw();
			}
			
		});
		ToolItem redoItem = new ToolItem(toolBar, SWT.PUSH);
		redoItem.setText("redo");
		redoItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				viewsManager.redo();
				canvas.redraw();
			}
			
		});
		
		ToolItem selectionModeItem = new ToolItem(toolBar, SWT.PUSH);
		selectionModeItem.setText("selection mode");
		selectionModeItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				editorMode = DragFiguresMode.instance;
				canvas.setCursor(editorMode.getCursor());
				canvas.redraw();
			}
			
		});
		
		ToolItem addActionStateModeItem = new ToolItem(toolBar, SWT.PUSH);
		addActionStateModeItem.setText("add action state mode");
		addActionStateModeItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				editorMode = AddStateMode.instance;
				canvas.setCursor(editorMode.getCursor());
				canvas.redraw();
			}
			
		});
		
		ToolItem addTransitionModeItem = new ToolItem(toolBar, SWT.PUSH);
		addTransitionModeItem.setText("add transition mode");
		addTransitionModeItem.addSelectionListener(new SelectionListener() {

			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}

			public void widgetSelected(SelectionEvent e) {
				editorMode = AddTransitionMode.instance;
				canvas.setCursor(editorMode.getCursor());
				canvas.redraw();
			}
			
		});
		
		assert toolBar != null;
	}
}
